/* 	Authors: Ha Le Hoai Trung
 *	MSSV : 50402810
	Date: 3/12/2007
*/
package MP.staticchecker;
import java.util.*;


abstract public class Type {
	boolean isLeftCompatibleTo(Type a) {
		return false;
	}
}
abstract class PrimType extends Type {
	boolean isLeftCompatibleTo(Type a) {
		if (this.getClass().equals(a.getClass()))
			return true;
		return false;
	}
}
abstract class NumericType extends PrimType{}
class IntegerType extends NumericType {
	public String toString(){
		return "integer";
	}	
}



class RealType extends NumericType {
	boolean isLeftCompatibleTo(Type a) {
		if (a instanceof NumericType)
			return true;
		return false;
	}
	public String toString(){
		return "real";
	}
}



class BooleanType extends PrimType {
	public String toString(){
		return "boolean";
	}	
}	



class StringType extends PrimType {
	public String toString(){
		return "string";
	}	
}

class RangeType extends PrimType {
	int lower;
	int upper;
	
	public RangeType(int up, int low) {
		lower = low;
		upper = up;
	}
	boolean isLeftCompatibleTo(Type a) {
		if (a instanceof RangeType) {
			RangeType ra = (RangeType)a;
			if (upper == ra.upper && lower == ra.lower)
				return true;
			else
				return false;
		}
		return false;
	}
	public String toString() {
		return lower+".."+upper;
	}
}

class ArrayType extends Type {
	Type eType = null;
	Type iType = null;
	public ArrayType(Type e) {
		eType = e;
	}
	public ArrayType(Type index,Type element) {
		eType = element;
		iType = index;
	}
	//TODO
	boolean isLeftCompatibleTo(Type a) {
		ArrayType temp = (ArrayType) a;
		if(eType.isLeftCompatibleTo(temp.eType))
		{
			if(iType.isLeftCompatibleTo(temp.eType))
			{
				return true;
			}
		}
		return false;
	}
	public String toString(){
		RangeType range = (RangeType)iType;
		return "["+eType.toString()+","+String.valueOf(range.lower)+","+String.valueOf(range.upper)+"]";
	}
}
class VoidType extends PrimType{}
class FunctionType extends Type {
	Type pType = null;
	Type rType = null;
	
	public FunctionType(Type p, Type r) {
		pType = p;
		rType =r;
	}
	//TODO
	boolean isLeftCompatibleTo(Type a) {
		return false;
	}
	public String toString() {
		return (pType==null?"null":pType.toString())+"->"+rType.toString();
	}
}

class ProductType extends Type {
	Type e1Type = null;
	Type e2Type = null;

	public ProductType(Type e1, Type e2) {
		e1Type = e1;
		e2Type = e2;
	}
	//TODO
	boolean isLeftCompatibleTo(Type a) {
		return false;
	}
	public String toString() {
		return e1Type.toString()+"*"+e2Type.toString();
	}
}	
			
//ParaType
class ParaType extends Type
{
	ArrayList pa;
	
	public ParaType(ArrayList paa)
	{
		pa = new ArrayList();		
		pa.addAll(0,paa);				
	}
	
	boolean isLeftCompatibleTo(Type a)
	{
		if(a instanceof ParaType)
		{
			ParaType aPT = (ParaType) a;
			if(pa.size() == aPT.pa.size())
			{
				for(int i = 0; i < pa.size(); i++)
				{
					/*System.out.println("" + i);
					if(pa.get(i) instanceof IntegerType)
						if(aPT.pa.get(i) instanceof IntegerType)
							System.out.println("dd");*/
						
					if((pa.get(i) instanceof IntegerType) && !(aPT.pa.get(i) instanceof IntegerType))
						return false;
					else if((pa.get(i) instanceof RealType) && !(aPT.pa.get(i) instanceof NumericType || aPT.pa.get(i) instanceof Integer))
						return false;
					else if((pa.get(i) instanceof StringType) && !(aPT.pa.get(i) instanceof StringType))
						return false;
					else if((pa.get(i) instanceof BooleanType) && !(aPT.pa.get(i) instanceof BooleanType))
						return false;
					else if((pa.get(i) instanceof ArrayType) && !(aPT.pa.get(i) instanceof ArrayType))
					{
						return false;
					}
					else if((pa.get(i) instanceof ArrayType) && (aPT.pa.get(i) instanceof ArrayType))
					{
						ArrayType tempa = (ArrayType) pa.get(i);
						ArrayType tempb = (ArrayType) aPT.pa.get(i);
						if(tempa.isLeftCompatibleTo(tempb))
							return true;
						else 
							return false;
					}
				}
				return true;
			}
		}
		return false;	
	}
}

//VarType
class VarType extends Type
{	
}

//ConstType
class ConstType extends Type
{
	Type Typekind;
	public ConstType(Type ki)
	{
		Typekind = ki;
	}
	boolean isLeftCompatibleTo(Type a)
	{
		return false;
	}	
}
